package main;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import java.net.Socket;
import java.util.Enumeration;
import java.util.Hashtable;

import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.table.AbstractTableModel;

import client.ClientData;

import worker.WorkerData;

import comm.ConnectionType;



public class Gui extends JApplet implements ActionListener {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private JTextField inputNumPlaces;
	
	private String serverAddress="127.0.0.1";
	private int serverPort=10001;
	private JButton connect;
	
	private Hashtable<Integer, WorkerData> workerDataVector = new Hashtable<Integer, WorkerData>();
	private Hashtable<Integer, ClientData> clientDataVector = new Hashtable<Integer, ClientData>();
	
	WorkerTableModel workerTableModel;
	ClientTableModel clientTableModel;
	
	protected Long[] workerKeys = new Long[65535];
	protected Long[] clientKeys = new Long[65535];
	private ObjectInputStream in;
	private ObjectOutputStream out;
	public void init() {
		// Set up the text input boxes
		gui();
		try {
			Socket socket = new Socket(this.serverAddress, this.serverPort);
			in = new ObjectInputStream(
					socket.getInputStream());
			out = new ObjectOutputStream(
					socket.getOutputStream());
			out.writeObject(ConnectionType.ADMIN);
			Listener l = new Listener(socket);
			l.start();
			Command c = new Command();
			c.start();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}





	}
	class Command extends Thread{

		public void run(){
			while(true){

				BufferedReader br = new BufferedReader(new InputStreamReader(System.in) );
				try {
					String cmd = br.readLine();

					synchronized (out) {
						out.writeObject(ConnectionType.KILL_CLIENT);
						out.writeObject( Long.parseLong(cmd));
					}

				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

			}
		}

	}
	private class Listener extends Thread{

		private Socket socket;
		private int time = 3000;
		public Listener(Socket socket) {
			super();

			this.socket = socket;
		}


		@SuppressWarnings("unchecked")
		public void run(){
			new TimeToUpdate().start();
			while (true){
				try {
					ConnectionType ct = (ConnectionType)in.readObject();
					switch (ct) {
					case FULL_UPDATE:
						workerDataVector = (Hashtable<Integer, WorkerData>) in.readObject();
						clientDataVector = (Hashtable<Integer, ClientData>) in.readObject();
					
						if(workerDataVector.keySet() !=  null){
							workerKeys =  workerDataVector.keySet().toArray(workerKeys);
							workerTableModel.fireTableDataChanged();
						} else { 
							workerKeys = null;
						}
						if(clientDataVector.keySet() !=  null){
							clientKeys =  clientDataVector.keySet().toArray(clientKeys);
							clientTableModel.fireTableDataChanged();
						} else { 
							clientKeys = null;
						}
						
						break;

					default:
						break;
					}

				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
					return;
				} catch (ClassNotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
					return;
				}

			}
		}
		private class TimeToUpdate extends Thread{


			public TimeToUpdate() {
				super();

			}

			public void run(){
				while(true){
					try {
						synchronized (out) {
							out.writeObject(ConnectionType.FULL_UPDATE);
						}
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					try {
						Thread.sleep(time);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}

			}

		}

	}

	class PopUpDemo extends JPopupMenu {
	    /**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		JPopupMenu anItem;
	    public PopUpDemo(){
	        anItem = new JPopupMenu("Click Me!");
	        add(anItem);
	    }
	}
	 private void doPop(MouseEvent e){
	        PopUpDemo menu = new PopUpDemo();
	        menu.show(e.getComponent(), e.getX(), e.getY());
	    }

	private void gui(){
		this.setSize(1000, 400);
		Container container = getContentPane();

		JPanel inputPanel = new JPanel();
		inputPanel.add(new JLabel(" ", SwingConstants.RIGHT));
		inputNumPlaces = new JTextField(3);
		inputPanel.add(inputNumPlaces);
		inputNumPlaces.addActionListener(this);
		container.add(inputPanel, "North");

		JPanel textPanel = new JPanel();


		workerTableModel = new WorkerTableModel();
		clientTableModel = new ClientTableModel();
		final JTable jTableWorker = new JTable(workerTableModel);
		final JTable jTableClient = new JTable(clientTableModel);
		getContentPane().add(new JScrollPane(jTableWorker),BorderLayout.WEST);
		getContentPane().add(new JScrollPane(jTableClient),BorderLayout.EAST);


		JPanel buttonPanel = new JPanel();

		connect = new JButton("connect");
		connect.addActionListener(this);

		buttonPanel.add(connect);
		container.add(buttonPanel, "South");
		jTableWorker.addMouseListener( new MouseAdapter()
		{
			public void mouseClicked( MouseEvent e )
			{
				
				// Left mouse click
				if ( SwingUtilities.isLeftMouseButton( e ) )
				{
					// Do something
					System.out.println("OPS");
				}
				// Right mouse click
				else if ( SwingUtilities.isRightMouseButton( e ))
				{
					// get the coordinates of the mouse click
					Point p = e.getPoint();
					 doPop(e);
					// get the row index that contains that coordinate
					int rowNumber = jTableWorker.rowAtPoint( p );
		 System.out.println(rowNumber);
		 System.out.println(jTableWorker.getComponentAt(0, rowNumber));
					// Get the ListSelectionModel of the JTable
					ListSelectionModel model = jTableWorker.getSelectionModel();
		 
					// set the selected interval of rows. Using the "rowNumber"
					// variable for the beginning and end selects only that one row.
					model.setSelectionInterval( rowNumber, rowNumber );
				}
			}
		});
	}
	class updater extends Thread {

		public void run() {
			while (true) {
				OperatingSystemMXBean OSMXBean = ManagementFactory
				.getOperatingSystemMXBean();
				String str = String.valueOf(Math.round(OSMXBean
						.getSystemLoadAverage()));
				System.out.println(str);
				inputNumPlaces.setText(str);
				try {
					Thread.sleep(3000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}

	}

	@Override
	public void actionPerformed(ActionEvent arg0) {
		// TODO Auto-generated method stub
		Object source = arg0.getSource();

		if (source == inputNumPlaces) {
			try {


			}

			catch (NumberFormatException e) {
				JOptionPane.showMessageDialog(this, "teste", "teste!",
						JOptionPane.ERROR_MESSAGE);
			}

		} else if (source == connect) { // connect text area

		}

	}
	
	class WorkerTableModel extends AbstractTableModel{

		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		@Override
		public int getColumnCount() {
			// TODO Auto-generated method stub
			return 9;
		}

		@Override
		public int getRowCount() {
			// TODO Auto-generated method stub
			return workerDataVector.size();
		}
		public String getColumnName(int x) {
			switch (x) {
			case 0:
				return "ID";
			case 1:
				return "IP";
			case 2:
				return "Port";
			case 3:
				return "Nr Cores";
			case 4:
				return "O.S.";
			case 5:
				return "Farming Time";
			case 6:
				return "Tasks Processed";
			case 7:
				return "Average time/Task";
			case 8:
				return "Start Time";
			}
			return "Unknown";
		}

		@Override
		public Object getValueAt(int y, int x) {
			WorkerData workerData = workerDataVector.get(workerKeys [workerDataVector.size()- y - 1]);
			switch (x) {
			case 0:
				return workerData.getId();
			case 1:
				return workerData.getWorkerAddress();
			case 2:
				return workerData.getWorkerPort();
			case 3:
				return workerData.getNumberOfProcessors();
			case 4:
				return workerData.getOperatingSystem();
			case 5:
				return  workerData.getTotalTimeSpentFarming();
			case 6:
				System.out.println(workerData.getNumberOfTasksProcessed());
				System.out.println(workerData.getAverageTimePerTask());
				return workerData.getNumberOfTasksProcessed();
			case 7:
				return workerData.getAverageTimePerTask();
			case 8:
				return workerData.getStartTime();
			}
			return "Unknown";

		}


	}
	class ClientTableModel extends AbstractTableModel{

		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		@Override
		public int getColumnCount() {
			// TODO Auto-generated method stub
			return 8;
		}

		@Override
		public int getRowCount() {
			// TODO Auto-generated method stub
			return clientDataVector.size();
		}
		public String getColumnName(int x) {
			switch (x) {
			case 0:
				return "ID";
			case 1:
				return "IP";
			case 2:
				return "Port";
			case 3:
				return "Priority";
			case 4:
				return "Problem Nr";
			case 5:
				return "Version";
			case 6:
				return "Task Counter";
			case 7:
				return "Tasks Done";
			}
			return "Unknown";
		}

		@Override
		public Object getValueAt(int y, int x) {
			ClientData clientData = clientDataVector.get(clientKeys [clientDataVector.size()- y - 1]);
			switch (x) {
			case 0:
				return clientData.getId();
			case 1:
				return clientData.getIpAdress();
			case 2:
				return clientData.getPort();
			case 3:
				return clientData.getClientPriority();
			case 4:
				return clientData.getProblemNumber();
			case 5:
				return  clientData.getVersion();
			case 6:
				return clientData.getTaskCounter();
			case 7:
				return clientData.getTotalNumberOfTasksDone();
			}
			return "Unknown";

		}


	}
}
